var Editor = {
    // toolbar
    getButtons: function(editor) {
        var result = [
            //this.mkPanel(gettext('Headers') + ':', [
            this.mkTitle(gettext('Headers') + ':'),
                this.mkButton('H1', gettext('Header 1'), function() {
                    editor.execCommand('formatblock', false, 'h1');
                    editor.saveContent();
                }),
                this.mkButton('H2', gettext('Header 2'), function() {
                    editor.execCommand('formatblock', false, 'h2');
                    editor.saveContent();
                }),
                this.mkButton('H3', gettext('Header 3'), function() {
                    editor.execCommand('formatblock', false, 'h3');
                    editor.saveContent();
                }),
                this.mkButton('H4', gettext('Header 4'), function() {
                    editor.execCommand('formatblock', false, 'h4');
                    editor.saveContent();
                }),
                this.mkButton('H5', gettext('Header 5'), function() {
                    editor.execCommand('formatblock', false, 'h5');
                    editor.saveContent();
                })
            //]),
            ,
            //this.mkPanel(gettext('Text') + ':', [
            this.mkTitle(gettext('Text') + ':'),
                this.mkButton('P', gettext('Paragraph'), function() {
                    editor.execCommand('formatblock', false, 'p');
                    editor.saveContent();
                }),
                this.mkButton('OL', gettext('Ordered list'), function() {
                    editor.execCommand('insertorderedlist', false, 'ul');
                    editor.saveContent();
                }),
                this.mkButton('UL', gettext('Unordered list'), function() {
                    editor.execCommand('insertunorderedlist', false, 'ul');
                    editor.saveContent();
                })
            //]),
            ,
            //this.mkPanel(gettext('Font') + ':', [
            this.mkTitle(gettext('Font') + ':'),
                 this.mkButton('<b>B</b>', gettext('Bold'), function() {
                     editor.execCommand('bold', false, null);
                     editor.saveContent();
                 }),
                 this.mkButton('<i>I</i>', gettext('Italic'), function() {
                     editor.execCommand('italic', false, null);
                     editor.saveContent();
                 }),
                 this.mkButton('<s>S</s>', gettext('Striked'), function() {
                     editor.execCommand('strikethrough', false, null);
                     editor.saveContent();
                 })
             //]),
             ,
            //this.mkPanel(gettext('Objects') + ':', [
             this.mkTitle(gettext('Objects') + ':'),
                this.mkButton(gettext('Image'), gettext('Insert image'), function() {
                    var link = prompt(gettext('URL'));
                    if (!link) return;
                    //editor.execCommand('insertimage', false, 'url(' + link + ')');
                    editor.execCommand('insertimage', false, link);
                    editor.saveContent();
                }),
                this.mkButton(gettext('Link'), gettext('Mark as link'), function() {
                    var link = prompt(gettext('URL'));
                    if (!link) return;
                    editor.execCommand('createlink', false, link);
                    editor.saveContent();
                })
            //]),
            ,
            this.mkTitle(gettext('Tools') + ':'),
            //this.mkPanel(gettext('Tools') + ':', [
                this.mkButton(gettext('Clear'), gettext('Clear all formatting'), function() {
                    editor.execCommand('removeformat', false, null);
                    editor.saveContent();
                })
            //])
        ];

        var lst = editor.getElementsByClassName('debug_css');
        result.push(
        //result[result.length - 1].appendChild(
            this.mkCheckbox(gettext('Debug'),
                'editor_debug',
                function() {
                    for (var i=0; i < lst.length; i++) lst[i].disabled = false;
                },
                function() {
                    for (var i=0; i < lst.length; i++) lst[i].disabled = true;
                },
                true
            )
        );
        return result;

    },
    /**
     * opts = {
     *     root: root_element,
     *     css: [css_link1, css_link2, ...],
     *     debug_css: [css_link1, css_link2, ...]
     * }
     */
    create: function(opts) {
        var self = this;
        var box = document.createElement('div');
        box.className = 'editor_box';
        opts.root.appendChild(box);

        // editor
        var iframe = document.createElement('iframe');
        iframe.src = '';
        box.appendChild(iframe);

        var editor = iframe.contentDocument;
        editor.id = opts.id;

        editor.open();
        editor.write('<html>');
        editor.write('<head>');
        for (var i=0; i < opts.css.length; i++) {
            editor.write('<link rel="stylesheet" type="text/css" href="' + opts.css[i] + '">');
        };
        for (var i=0; i < opts.debug_css.length; i++) {
            editor.write('<link rel="stylesheet" type="text/css" href="' + opts.debug_css[i] + '" class="debug_css">');
        };
        editor.write('</head>');
        editor.write('<body></body>');
        editor.write('</html>');
        editor.close();

        //alert(editor.head.innerHTML);

        editor.designMode = 'on';
        try { editor.execCommand('useCSS', false, false); } catch (e) {}
        try { editor.execCommand('styleWithCSS', false, false); } catch (e) {}

        editor.addEventListener('paste', function(e) {
            var text = e.clipboardData.getData('text');
            editor.execCommand('inserthtml', false, self.fullHtmlCleanup(text));
            if (e.preventDefault) e.preventDefault();
        }, false);

        var toolbar = document.createElement('div');
        toolbar.className = 'toolbar';
        box.insertBefore(toolbar, iframe);

        var buttons = self.getButtons(editor);
        for (var i = 0; i < buttons.length; i++) {
            toolbar.appendChild(buttons[i]);
        }

        editor.fixContent = function() {
            try {
                self.fixDocument(editor);
            } catch(e) {
                console.log('fixDocument error: ' + e);
            }
        };

        editor.saveContent = function() {
            editor.fixContent();
            editor.save(editor.body.innerHTML);
        };

//        editor.onkeyup = function() {
//            editor.saveContent();
//        };
        if (document.addEventListener) {
            editor.addEventListener("keyup", function() { editor.saveContent(); }, true);
        } else {
            editor.onkeyup = function() { editor.saveContent(); };
        }

        // API
        editor.save = function(content) {
        }
        editor.update = function(content) {
            editor.body.innerHTML = content;
            editor.fixContent();
        };
        editor.iframe = iframe;

        return editor;

    },
    mkButton: function(title, hint, onclick) {
        var button = document.createElement('button');
        button.innerHTML = title;
        button.title = hint;
        button.onclick = function() {
            onclick();
            return false;
        }
        return button;
    },
    mkCheckbox: function(title, name, onEnabled, onDisabled, enabledByDefault) {
        var box = document.createElement('span');
        box.className = 'cb_box';

        var cb = document.createElement('input');
        cb.id = 'cb_' + name;
        cb.type = 'checkbox';
        cb.init = function() {
            if (localStorage[cb.id + '_value'] == '1') {
                cb.checked = true;
            } else if (localStorage[cb.id + '_value'] == '0') {
                cb.checked = false;
            } else {
                cb.checked = !!enabledByDefault;
            }
            (cb.checked ? onEnabled : onDisabled)();
        };
        cb.onchange = function() {
            if (cb.checked) {
                localStorage[cb.id + '_value'] = '1';
                onEnabled();
            } else {
                localStorage[cb.id + '_value'] = '0';
                onDisabled();
            }
        };

        var label = document.createElement('label');
        label.htmlFor = cb.id;
        label.innerHTML = title;

        box.appendChild(cb);
        box.appendChild(label);

        cb.init();
        return box;
    },
    mkTitle: function(title) {
        var el = document.createElement('span');
        el.innerHTML = '&nbsp;' + title;
        return el;
    },
    mkSplitter: function() {
        return mkTitle('&nbsp;');
    },
    mkPanel: function(title, buttons) {
        var el = document.createElement('div');
        el.className = 'subtoolbar';
        el.appendChild(this.mkTitle(title));
        for (var i = 0; i < buttons.length; i++) {
            el.appendChild(buttons[i]);
        }
        el.innerHTML += '\n ';
        return el;
    },
    fullHtmlCleanup: function(s) {
        return s.replace(/<[^>]+>/g, '');
    },
    prettyHtml: function(s) {
        // add two newlines after closed tag
        s = s.replace(/<\/(h[123456]|p|ol|ul|dl|dt|dd|li|div|address|blockquote|center|del|hr|ins|noscript|pre|script|table)>(\S)/gi, '</$1>\n\n$2');

        // add one newline after closed tag
        s = s.replace(/<\/(li|td|tr|tbody|thead)>(\S)/gi, '</$1>\n$2');

        // add newline after self-closed tag
        s = s.replace(/<(hr|br)\s*\/?>(\S)/gi, '<$1 />\n$2');

        // add newline after open tag
        s = s.replace(/<(div|ol|ul|table|thead|tbody|tr|td|th)([^>]*)>(\S)/gi, '<$1$2>\n$3');

        // add newline before open tag
        s = s.replace(/(\S)<(div|ol|ul|h[123456]|table|thead|tbody|tr|td)([^>]*)>/gi, '$1\n<$2$3>');

        return s;
    },
    fixDocument: function(doc) {

        // trash spans
        var spans = doc.body.getElementsByClassName('Apple-style-span');
        for (var i = 0; i < spans.length; i++) {
            spans[i].outerHTML = spans[i].innerText;
        }

        // wrap empty content with <p></p>
        if (doc.body.innerText != '' &&
            doc.body.innerText == doc.body.innerHTML
        ) {
            doc.execCommand('formatblock', false, 'p');
        }

//        FIXME: focus() to new element

//        // clean div => p
//        var divs = doc.body.getElementsByTagName('div');
//        for (var i = 0, div, p; i < divs.length; i++) {
//            div = divs[i];
//            if (div.attributes.length == 0) {
//                p = doc.createElement('p');
//                div.parentNode.insertBefore(p ,div.nextSibling);
//                for (var j = 0; j < div.childNodes.length; j++) {
//                    p.appendChild(div.childNodes[j]);
//                };
//                div.parentNode.removeChild(div);
//                //doc.iframe.focus();
//            }
//        }
    }
}

function init_simple_visual_editor(opts) {
    function $(id)   { return document.getElementById(id); }
    function mk(tag) { return document.createElement(tag); }

    var code_textarea = opts.textarea;

    var place = mk('div');
    code_textarea.parentNode.insertBefore(place, code_textarea);

    var editor_tab_content = mk('div');

    var code_tab_content = mk('div');
    code_tab_content.appendChild(code_textarea);

    var tabs = createTabs([{
            title: gettext('Editor'),
            content: editor_tab_content,
            onswitch: function() { focusOnEditor(); }
        }, {
            title: 'HTML',
            content: code_tab_content,
            // doesnt work :-/
            onswitch: function() { code_textarea.focus(); }
        }],
        code_textarea.id + '_tabs'
    );
    place.appendChild(tabs);

    var editor = Editor.create({
        root: editor_tab_content,
        css: opts.css || [],
        debug_css: opts.debug_css || [],
        id: code_textarea.id + '_editor',
    });

    function focusOnEditor() {
        editor.iframe.focus();
    }

    code_textarea.onchange = function() {
        editor.update(code_textarea.value);
    };

    editor.save = function(value) {
        code_textarea.value = Editor.prettyHtml(editor.body.innerHTML);
    };

    code_textarea.onchange();
};